1 /*
  2  *  Copyright (C) 2004 Samsung Electronics 
  3  *             SW.LEE <hitchcar@samsung.com>
  4  *            - based on Russell King : pcf8583.c
  5  *            - added  smdk24a0, smdk2440
  6  *            - added  poseidon (s3c24a0+wavecom)       
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License version 2 as
 10  * published by the Free Software Foundation.
 11  *
 12  *  Driver for FIMC2.x Camera Decoder 
 13  *
 14  */
 15 
 16 //#include <linux/config.h>
 17 #include <linux/module.h>
 18 #include <linux/kernel.h>
 19 #include <linux/init.h>
 20 #include <linux/i2c.h>
 21 #include <linux/i2c-id.h>
 22 #include <linux/slab.h>
 23 #include <linux/string.h>
 24 #include <linux/init.h>
 25 #include <linux/delay.h>
 26 
 27 //#define CAMIF_DEBUG
 28 
 29 //#include <asm/arch/registers.h>
 30 #include "../s3c_camif.h"
 31 #include "mt9d111.h"
 32 
 33 static struct i2c_driver sensor_driver;
 34 
 35 /* This is an abstract CIS sensor for MSDMA input. */
 36 
 37 camif_cis_t msdma_input = {
 38         itu_fmt:       CAMIF_ITU601,
 39         order422:      CAMIF_YCBYCR,            /* YCRYCB */
 40         camclk:        32000000,                /* No effect */
 41         source_x:      800,       
 42         source_y:      480,
 43         win_hor_ofst:  0,
 44         win_ver_ofst:  0,
 45         win_hor_ofst2: 0,
 46         win_ver_ofst2: 0,
 47         polarity_pclk: 0,
 48         polarity_vsync:1,
 49         polarity_href: 0,
 50         reset_type:CAMIF_EX_RESET_AL, /* Ref board has inverted signal */
 51         reset_udelay: 20000,
 52 };
 53 
 54 camif_cis_t interlace_input = {
 55         itu_fmt:       CAMIF_ITU601,
 56         order422:      CAMIF_YCBYCR,            /* YCRYCB */
 57         camclk:        32000000,                /* No effect */
 58         source_x:      720,       
 59         source_y:      243,
 60         win_hor_ofst:  0,
 61         win_ver_ofst:  0,
 62         win_hor_ofst2: 0,
 63         win_ver_ofst2: 0,
 64         polarity_pclk: 1,
 65         polarity_vsync:0,
 66         polarity_href: 0,
 67         reset_type:CAMIF_EX_RESET_AL, /* Ref board has inverted signal */
 68         reset_udelay: 20000,
 69 };
 70 
 71 static camif_cis_t data = {
 72         itu_fmt:       CAMIF_ITU601,
 73         order422:      CAMIF_CBYCRY,
 74         camclk:        19000000,
 75         source_x:      640,       
 76         source_y:      480,
 77         win_hor_ofst:  0,
 78         win_ver_ofst:  0,
 79         win_hor_ofst2: 0,
 80         win_ver_ofst2: 0,
 81         polarity_pclk: 0,
 82                 polarity_vsync:1,
 83         polarity_href: 0,
 84         reset_type: CAMIF_EX_RESET_AL,          /* Ref board has inverted signal */
 85         reset_udelay: 1000,
 86 };
 87 
 88 camif_cis_t* get_initialized_cis(void)
 89 {
 90         if(data.init_sensor == 0) return NULL;
 91         return &data;
 92 }
 93 
 94 #define CAM_ID 0xBA
 95 
 96 static unsigned short ignore[] = { I2C_CLIENT_END };
 97 static unsigned short normal_addr[] = { (CAM_ID >> 1), I2C_CLIENT_END };
 98 static unsigned short *forces[] = { NULL };
 99 
100 static struct i2c_client_address_data addr_data = {
101       normal_i2c:normal_addr,
102       //normal_i2c_range:ignore,
103       probe:ignore,
104       //probe_range:ignore,
105       ignore:ignore,
106       //ignore_range:ignore,
107       forces:forces,
108 };
109 
110 
111 unsigned char sensor_read(struct i2c_client *client, unsigned char subaddr)
112 {
113         int ret;
114         unsigned char buf[2];
115         struct i2c_msg msg_wr = { client->addr, 0, 1, buf };
116         struct i2c_msg msg_rd = { client->addr, 0, 2, buf };
117 
118         memset(buf, 0, 2);
119         buf[0] = subaddr;
120 
121         ret = i2c_transfer(client->adapter, &msg_wr, 1) == 1 ? 0 : -EIO;
122         if (ret == -EIO) {
123                 printk(" I2C write Error \n");
124                 return -EIO;
125         }
126 
127         msg_rd.flags = I2C_M_RD;
128         ret = i2c_transfer(client->adapter, &msg_rd, 1) == 1 ? 0 : -EIO;
129 
130         return buf[0];
131 }
132 
133 
134 static int
135 sensor_write(struct i2c_client *client, unsigned char subaddr, unsigned short val)
136 {
137         unsigned char buf[3];
138         struct i2c_msg msg = { client->addr, 0, 3, buf };
139         int ret;
140 
141         buf[0] = subaddr;
142         buf[1] = val >> 8;
143         buf[2] = val;
144 
145         ret = i2c_transfer(client->adapter, &msg, 1) == 1 ? 0 : -EIO;
146         return ret;
147 }
148 
149 static int mt9d111_set_regs(struct i2c_client *sam_client, const struct mt9d111_reg *regP)
150 {
151         u32 curReg = 0;
152         u16 regVal;
153         int status = 0;
154         int curPage = -1;
155 
156         /* The list is a register number followed by the value */
157         while( regP[curReg].page != MT9D111_TERM )
158         {
159                 if (curPage != regP[curReg].page)
160                 {
161                         if (regP[curReg].page == 0)
162                         {
163                                 regVal = 0;
164                                 status = (sensor_write(sam_client, 0xF0, regVal) == 0) ? 0 : -EIO;
165                         }
166                         if (regP[curReg].page == 1)
167                         {
168                                 regVal = 1;
169                                 status = (sensor_write(sam_client, 0xF0, regVal) == 0) ? 0 : -EIO;
170                         }
171                         if (regP[curReg].page == 2)
172                         {
173                                 regVal = 2;
174                                 status = (sensor_write(sam_client, 0xF0, regVal) == 0) ? 0 : -EIO;
175                         }
176                         curPage = regP[curReg].page;
177                 }
178                 if (regP[curReg].page == MT9D111_DELAY)
179                 {
180                         mdelay(regP[curReg].value);
181                         curReg++;
182                         continue;
183                 }
184 
185                 regVal = regP[curReg].value;
186                 sensor_write(sam_client, regP[curReg].subaddr, regP[curReg].value);
187 
188                 curReg++;
189         }
190 }
191 
192 void inline sensor_init(struct i2c_client *sam_client)
193 {
194         mt9d111_set_regs(sam_client, mt9d111Init);
195 
196 }
197 
198 static int
199 s5k3xa_attach(struct i2c_adapter *adap, int addr, int kind)
200 {
201         struct i2c_client *c;
202  
203         c = kmalloc(sizeof(*c), GFP_KERNEL);
204         if (!c)
205                 return -ENOMEM;
206 
207         memset(c, 0, sizeof(struct i2c_client));            
